
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Xml.Linq;
using System.Linq;
using System.Text.RegularExpressions;

namespace Hanselminutes
{
	public abstract class ShowRepository
	{
		readonly string _documents = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
		
		string _localPath;
		string _url;

		Show[] _shows = new Show[0];

		public ShowRepository (string url, string filename)
		{
			_url = url;
			_localPath = Path.Combine (_documents, filename);
			
			if (HasLocalData) {
				_shows = ParseShows (File.ReadAllText (_localPath));
			}
		}

		public IEnumerable<Show> AllShows {
			get { return _shows; }
		}

		void SaveLocal (string data)
		{
			File.WriteAllText (_localPath, data);
		}

		public DateTime GetLastRefreshTimeUtc ()
		{
			if (HasLocalData) {
				return new FileInfo (_localPath).LastWriteTimeUtc;
			} else {
				return new DateTime (1990, 1, 1);
			}
		}

		public bool HasLocalData {
			get { return File.Exists (_localPath); }
		}

		public void Refresh (Action action)
		{			
			var webClient = new WebClient ();
			
			webClient.DownloadStringCompleted += (sender, e) =>
			{
				try {
					SaveLocal (e.Result);
					_shows = ParseShows (e.Result);
				} catch (Exception ex) {
					Console.WriteLine ("ERROR saving downloaded XML: " + ex);
				}
				action ();
			};
			
			webClient.DownloadStringAsync (new Uri (_url));
		}

		protected abstract Show[] ParseShows (string xml);
		
		public abstract void BeginGetComments(Show show, Action<Comment[]> action);

		protected static DateTime ParseDateTime (string date)
		{
			var ps = date.Split (' ');
			var justDt = string.Join (" ", ps.Skip (1).Take (4).ToArray ());
			return DateTime.Parse (justDt);
		}

		protected static string StripHtml(string html) {
			var h = html.Replace("&nbsp;", " ");
			var hdoc = XDocument.Parse("<html>" + h + "</html>");
			return hdoc.Root.Value;			
		}
	}

	public class Hanselminutes : ShowRepository
	{
		const string FileName = "Hanselminutes.xml";
		const string Url = "http://feeds.feedburner.com/HanselminutesCompleteMP3";
		
		public Hanselminutes() : base(Url, FileName) {
		}
		
		protected override Show[] ParseShows (string xml)
		{
			var xDoc = XDocument.Parse (xml);
			XNamespace ns = "";
			
			var guidRe = new System.Text.RegularExpressions.Regex (@"ShowID=(\d+)");
			
			Console.WriteLine ("Found " + xDoc.Descendants (ns + "item").Count () + " shows");
			var q = from p in xDoc.Descendants (ns + "item")
					select new Show (p.Element (ns + "enclosure").Attributes ("url").First ().Value) {
				ShowNumber = int.Parse (guidRe.Match (p.Element (ns + "guid").Value).Groups[1].Value),
				Title = p.Element (ns + "title").Value, 
				Description = p.Element (ns + "description").Value,
				PublishedDate = ParseDateTime (p.Element (ns + "pubDate").Value)
			};
			
			return q.ToArray ();
		}
		
		public override void BeginGetComments(Show show, Action<Comment[]> action) {
			var acct = "41970964d3b934f217b95a982c4083d6";
			var idInfoUrl = string.Format("http://intensedebate.com/js/genericCommentWrapper2.php?acct={0}&postid=http%3A%2F%2Fwww.hanselminutes.com%2Fdefault.aspx%3FshowID%3D{1}&title=%0A%09Hanselminutes%0A&url=http%3A%2F%2Fwww.hanselminutes.com%2Fdefault.aspx%3FshowID%3D{1}",
				acct, show.ShowNumber);
			
			
			var idInfoClient = new WebClient();
			idInfoClient.DownloadStringCompleted += (s, e) => {
				var json = e.Result;
				
				var postIdRe = new System.Text.RegularExpressions.Regex(acct + @"/generic/(\d+)+");
				var postId = postIdRe.Match(json).Groups[1].Value;
				
				var rssUrl = "http://intensedebate.com/postRSS/" + postId;
				
				var rssClient = new WebClient();
				rssClient.DownloadStringCompleted += (ss, ee) => {
					
					var rss = ee.Result;
					
					action(Comment.ParseRss(rss));
					
				};
				rssClient.DownloadStringAsync(new Uri(rssUrl));
				
			};
			idInfoClient.DownloadStringAsync(new Uri(idInfoUrl));
		}
	}
	
	public class HanselminutesOn9 : ShowRepository
	{
		const string FileName = "HanselminutesOn9.xml";
		const string Url = "http://channel9.msdn.com/tags/HanselminutesOn9/feed/ipod/";
		
		public HanselminutesOn9() : base(Url, FileName) {
		}
		
		protected override Show[] ParseShows (string xml)
		{
			var xDoc = XDocument.Parse (xml);
			XNamespace ns = "";
			
			var prefix = "Hanselminutes on 9 -";
			
			Console.WriteLine ("Found " + xDoc.Descendants (ns + "item").Count () + " shows");
			var q = from p in xDoc.Descendants (ns + "item")
					let rawTitle = p.Element (ns + "title").Value
					let cleanTitle = rawTitle.StartsWith(prefix) ? rawTitle.Substring(prefix.Length).Trim() : rawTitle
					let desc = StripHtml(p.Element (ns + "description").Value)
					let url = p.Element (ns + "enclosure").Attribute ("url").Value
					select new Show (url) {
						Title = cleanTitle, 
						Description = desc, 
						PublishedDate = ParseDateTime (p.Element (ns + "pubDate").Value),
						CommentsUrl = p.Element (ns + "comments").Value
					};

			return q.ToArray ();
		}
		
		public override void BeginGetComments (Show show, Action<Comment[]> action)
		{
			var idInfoClient = new WebClient();
			idInfoClient.DownloadStringCompleted += (s, e) => {
				
				var cre = new Regex(@"\$create\(EvNet\.UI\.Toolbar, (\{""e.*?\}),\s", RegexOptions.Multiline);
				
				var matches = cre.Matches(e.Result);
				
				var comments = new List<Comment>();
				
				var first = true;
				
				foreach (Match m in matches) {				
					var comment = ParseComment(m.Groups[1].Value);
					if (comment != null) {
						if (!first) {
							comments.Add(comment);
						}
						first = false;
					}
				}
				
				action(comments.ToArray());
				
			};
			
			idInfoClient.DownloadStringAsync(new Uri(show.CommentsUrl));
		}
		
		Comment ParseComment(string json) {
			//Console.WriteLine ("> " + json);
			
			//var typeRe = new Regex(@"""Type"":""(\d+)""[,\}]", RegexOptions.Multiline);
			var authorRe = new Regex(@"""Name"":""(.*?)""[,\}]", RegexOptions.Multiline);
			var bodyRe = new Regex(@"""Body"":""(.*?)""[,\}]", RegexOptions.Multiline);
			
			//var typeM = typeRe.Match(json);
			var authorM = authorRe.Match(json);
			var bodyM = bodyRe.Match(json);
			
			if (authorM.Success && bodyM.Success) {
			
				var authorS = authorM.Groups[1].Value;
				var bodyS = bodyM.Groups[1].Value;
				
				Console.WriteLine ("a> " + authorS);
				Console.WriteLine ("b> " + bodyS);
				
				var author = System.Json.JsonPrimitive.Parse("\"" + authorS + "\"");
				var body = System.Json.JsonPrimitive.Parse("\"" + bodyS + "\"");
				
				return new Comment(body, author);
			}
			else {
				return null;
			}
		}

	}
}
